GIC: Add API to set/clear interrupt pending
authorJeenu Viswambharan <[email protected]>
Fri, 22 Sep 2017 07:32:09 +0000 (08:32 +0100)
committerJeenu Viswambharan <[email protected]>
Mon, 16 Oct 2017 15:50:02 +0000 (16:50 +0100)
API documentation updated.

Change-Id: I14e33cfc7dfa93257c82d76fae186b17a1b6d266
Co-authored-by: Yousuf A <[email protected]>
Signed-off-by: Jeenu Viswambharan <[email protected]>
docs/platform-interrupt-controller-API.rst
drivers/arm/gic/v2/gicv2_main.c
drivers/arm/gic/v3/gicv3_helpers.c
drivers/arm/gic/v3/gicv3_main.c
drivers/arm/gic/v3/gicv3_private.h
include/drivers/arm/gicv2.h
include/drivers/arm/gicv3.h
include/plat/common/platform.h
plat/common/plat_gicv2.c
plat/common/plat_gicv3.c

index df4139e3de1a33b277b4b2475924d20a05b8f7a3..d5c1673399f38f08f8e6b0c27f4fbb89a6d597a3 100644 (file)
@@ -243,6 +243,37 @@ In case of ARM standard platforms using GIC, the implementation of the API
 writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set
 the routing.
 
+Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should set the interrupt specified by first parameter ``id`` to
+*Pending*.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before setting interrupt pending,
+and writes to the GIC *Set Pending Register* to set the interrupt pending
+status.
+
+Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should clear the *Pending* status of the interrupt specified by first
+parameter ``id``.
+
+In case of ARM standard platforms using GIC, the implementation of the API
+writes to the GIC *Clear Pending Register* to clear the interrupt pending
+status, and inserts barrier to make memory updates visible afterwards.
+
 ----
 
 *Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
index f0b902cf972c73165341f9986f83a3e8862c38c5..eab4c3bfedcf426d788f131e20626ee27d7488ad 100644 (file)
@@ -438,3 +438,41 @@ void gicv2_set_spi_routing(unsigned int id, int proc_num)
 
        gicd_set_itargetsr(driver_data->gicd_base, id, target);
 }
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_clear_interrupt_pending(unsigned int id)
+{
+       assert(driver_data);
+       assert(driver_data->gicd_base);
+
+       /* SGIs can't be cleared pending */
+       assert(id >= MIN_PPI_ID);
+
+       /*
+        * Clear pending interrupt, and ensure that any shared variable updates
+        * depending on out of band interrupt trigger are observed afterwards.
+        */
+       gicd_set_icpendr(driver_data->gicd_base, id);
+       dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_set_interrupt_pending(unsigned int id)
+{
+       assert(driver_data);
+       assert(driver_data->gicd_base);
+
+       /* SGIs can't be cleared pending */
+       assert(id >= MIN_PPI_ID);
+
+       /*
+        * Ensure that any shared variable updates depending on out of band
+        * interrupt trigger are observed before setting interrupt pending.
+        */
+       dsbishst();
+       gicd_set_ispendr(driver_data->gicd_base, id);
+}
index ee874f92f77cccc6e12b5b74ff7e3cbbcb67870e..3abc6a5ca7507349149583bf5aa2c54453d73d8d 100644 (file)
@@ -194,6 +194,28 @@ unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id)
        return (reg_val >> bit_num) & 0x1;
 }
 
+/*
+ * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICPENDRR0.
+ */
+void gicr_set_icpendr0(uintptr_t base, unsigned int id)
+{
+       unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
+
+       gicr_write_icpendr0(base, (1 << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISPENDR0.
+ */
+void gicr_set_ispendr0(uintptr_t base, unsigned int id)
+{
+       unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
+
+       gicr_write_ispendr0(base, (1 << bit_num));
+}
+
 /*
  * Accessor to set the byte corresponding to interrupt ID
  * in GIC Re-distributor IPRIORITYR.
index c81ba9504ae4b7bef1393ec2064ab8cd9687e6e8..43dd77f126bb28f8f78d3e8de7a37b93870af6ff 100644 (file)
@@ -1037,3 +1037,55 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
                }
        }
 }
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI, and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+       assert(gicv3_driver_data);
+       assert(gicv3_driver_data->gicd_base);
+       assert(proc_num < gicv3_driver_data->rdistif_num);
+       assert(gicv3_driver_data->rdistif_base_addrs);
+
+       /*
+        * Clear pending interrupt, and ensure that any shared variable updates
+        * depending on out of band interrupt trigger are observed afterwards.
+        */
+       if (id < MIN_SPI_ID) {
+               /* For SGIs and PPIs */
+               gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+                               id);
+       } else {
+               gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
+       }
+       dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+       assert(gicv3_driver_data);
+       assert(gicv3_driver_data->gicd_base);
+       assert(proc_num < gicv3_driver_data->rdistif_num);
+       assert(gicv3_driver_data->rdistif_base_addrs);
+
+       /*
+        * Ensure that any shared variable updates depending on out of band
+        * interrupt trigger are observed before setting interrupt pending.
+        */
+       dsbishst();
+       if (id < MIN_SPI_ID) {
+               /* For SGIs and PPIs */
+               gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+                               id);
+       } else {
+               gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
+       }
+}
index 19fce2e73b9cf772c0528035252c6caa81599c62..43529c5a539a858287c1853f42c0c1ae1b9e8219 100644 (file)
@@ -72,6 +72,8 @@ void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
 void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
 void gicr_set_isenabler0(uintptr_t base, unsigned int id);
 void gicr_set_icenabler0(uintptr_t base, unsigned int id);
+void gicr_set_ispendr0(uintptr_t base, unsigned int id);
+void gicr_set_icpendr0(uintptr_t base, unsigned int id);
 void gicr_set_igroupr0(uintptr_t base, unsigned int id);
 void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
 void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
@@ -221,6 +223,11 @@ static inline unsigned int gicr_read_isenabler0(uintptr_t base)
        return mmio_read_32(base + GICR_ISENABLER0);
 }
 
+static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+{
+       mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
 static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
 {
        mmio_write_32(base + GICR_ISENABLER0, val);
index 6d224c3fb248b133794a2846953c2ef6ce31c958..bc2822ee1d9ca503cdbe364d4e98f9d8fbc7ed75 100644 (file)
@@ -172,6 +172,8 @@ void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
 void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
 void gicv2_raise_sgi(int sgi_num, int proc_num);
 void gicv2_set_spi_routing(unsigned int id, int proc_num);
+void gicv2_set_interrupt_pending(unsigned int id);
+void gicv2_clear_interrupt_pending(unsigned int id);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV2_H__ */
index 4f7cd8ab74ee10e3486141f44554082215412a39..09d6d808481c19bad0f5ef60defa73d4f7ff77c7 100644 (file)
@@ -387,6 +387,8 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
 void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
 void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
                u_register_t mpidr);
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __GICV3_H__ */
index 5c4e0588d5070c6a1546238a2e5257cc55a181b0..ab5d68ed5c614438d6cb564111895f91aea90814 100644 (file)
@@ -85,6 +85,8 @@ void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
 void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
 void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
                u_register_t mpidr);
+void plat_ic_set_interrupt_pending(unsigned int id);
+void plat_ic_clear_interrupt_pending(unsigned int id);
 
 /*******************************************************************************
  * Optional common functions (may be overridden)
index c30d872a7ffb08a19daab054fbc7adc7c7eef03d..646049489e2c628cb54be6b0e6cd4ab1461adc90 100644 (file)
@@ -262,3 +262,13 @@ void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
 
        gicv2_set_spi_routing(id, proc_num);
 }
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+       gicv2_set_interrupt_pending(id);
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+       gicv2_clear_interrupt_pending(id);
+}
index 7b3ea337e7c78a6e7fd771c7e2ebe85a3cf2f333..e5bf014d2800a69e01ce666e8ef4761e0f2110c2 100644 (file)
@@ -37,6 +37,8 @@
 #pragma weak plat_ic_set_interrupt_type
 #pragma weak plat_ic_raise_el3_sgi
 #pragma weak plat_ic_set_spi_routing
+#pragma weak plat_ic_set_interrupt_pending
+#pragma weak plat_ic_clear_interrupt_pending
 
 CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
        (INTR_TYPE_NS == INTR_GROUP1NS) &&
@@ -250,6 +252,20 @@ void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
 
        gicv3_set_spi_routing(id, irm, mpidr);
 }
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+       /* Disallow setting SGIs pending */
+       assert(id >= MIN_PPI_ID);
+       gicv3_set_interrupt_pending(id, plat_my_core_pos());
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+       /* Disallow setting SGIs pending */
+       assert(id >= MIN_PPI_ID);
+       gicv3_clear_interrupt_pending(id, plat_my_core_pos());
+}
 #endif
 #ifdef IMAGE_BL32